package com.example.factory;

import com.example.annotation.Autowired;
import com.example.annotation.Service;
import com.example.annotation.Transactional;
import com.example.utils.ClassUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.servlet.annotation.WebServlet;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 使用反射技术生厂对象
 */
public class BeanFactory {


    private static Map<String, Object> singletonMap = new HashMap<String, Object>();

    private static Map<String, List<String>> autowiredMap = new HashMap<String, List<String>>();//记录属性需要依赖到的bean


    static{
        try {
            List<Class<?>> classes = ClassUtil.getClasses("com.example");//扫描包
            List<String> isTransactionList = new ArrayList(); //记录需要添加事务的类 键名
            for (Class<?> aClass : classes) {
                Annotation[] annotations = aClass.getAnnotations();
                if(annotations.length > 0 && !aClass.isAnnotation()){ //判断扫描类上是否存在注解

                    String className = aClass.getName();
                    System.out.println(className);
                    Service service = aClass.getAnnotation(Service.class);
                    if(service != null){ //存在service注解向下执行创建实例装配到singletonMap中
                        Class<?> clazz = Class.forName(className);
                        String value = service.value();
                        Object o = clazz.newInstance();
                        singletonMap.put(value, o);
                        Field[] declaredFields = aClass.getDeclaredFields();
                        List<String> list = null; //记录需要依赖到的bean的id值
                        if(declaredFields.length > 0) //判断是否有属性
                            for (Field declaredField : declaredFields) {
                                if(list == null)
                                    list = new ArrayList<>();
                                Autowired autowired = declaredField.getAnnotation(Autowired.class);
                                if(autowired != null){ //通过Autowired注解判断属性是否有需要依赖到其他的Bean，有则添加到list
                                    String value1 = autowired.value();
                                    list.add(value1);
                                }
                            }

                        if(list != null && list.size() > 0) //将bean下属性需要依赖到的bean的id的list存放到autowiredMap下
                            autowiredMap.put(value, list);

                        //判断是否有Transactional注解，有则添加到isTransactionList中
                        Transactional transactional = aClass.getAnnotation(Transactional.class);
                        if(transactional != null){
                            isTransactionList.add(value);
                        }
                    }

                }
            }

            //对bean之间的互相依赖重新赋值。
            Set<Map.Entry<String, List<String>>> entries = autowiredMap.entrySet();
            Iterator<Map.Entry<String, List<String>>> iterator = entries.iterator();
            while (iterator.hasNext()){
                Map.Entry<String, List<String>> next = iterator.next();
                String key = next.getKey();
                Object o = singletonMap.get(key);
                Class<?> clazz = o.getClass();
                List<String> value = next.getValue();
                for (String str : value) {
                    Field declaredField = clazz.getDeclaredField(str);
                    declaredField.setAccessible(true);
                    Object o1 = singletonMap.get(str);
                    declaredField.set(o, o1);
                }
            }

            //对类上需要使用到Transaction的类做动态代理处理
            for (String s : isTransactionList) {
                Object o = singletonMap.get(s);
                Class<?> clazz = o.getClass();
                ProxyFactory proxyFactory = (ProxyFactory)singletonMap.get("proxyFactory");
                Class<?>[] isInterface = clazz.getInterfaces();//判断类上是否有接口，有则使用jdk否则是否cglib
                if (isInterface != null && isInterface.length > 0){
                    Object jdkProxy = proxyFactory.getJDKProxy(o);
                    singletonMap.put(s,jdkProxy);
                }else{
                    Object cglibProxy = proxyFactory.getCglibProxy(o);
                    singletonMap.put(s,cglibProxy);
                }
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    //初始化方法，在ContextLoaderListener中调用，初始化静态代码块
    public static void init(){

    }


    public static Object getBean(String id){
        return singletonMap.get(id);
    }

}
